﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Swift;
using SCM;
using Swift.Math;

namespace Server
{
    /// <summary>
    /// 战斗房间
    /// </summary>
    public class Room4Server : Room
    {
        public static Action<Room4Server, string> OnBattleEnded;

        // 所有房间内的用户会话，包括玩家和观战用户
        List<Session> ss = new List<Session>();

        public int WinnerAward = 0; // 胜者奖励
        public int LoserAward = 0; // 败者奖励
        public string[] WinnerAwardUnits; // 胜者的奖励单位

        // PVE room
        public Room4Server(string id, string aiID, Session s, Vec2 mapSize, string lvID)
        {
            Init(id, mapSize, lvID, aiID, s.ID, null, s.Usr.Info);
            AddSession(s);
        }

        // PVP room
        public Room4Server(string id, Session s1, Session s2, Vec2 mapSize, string lvID)
        {
            Init(id, mapSize, lvID, s1.ID, s2.ID, s1.Usr.Info, s2.Usr.Info);
            AddSession(s1);
            AddSession(s2);
        }

        // 进人
        public void AddSession(Session s)
        {
            if (ss.Contains(s))
                return;

            ss.Add(s);
        }

        // 走人
        public void RemoveSession(Session s)
        {
            if (!ss.Contains(s))
                return;

            ss.Remove(s);
        }

        // 广播消息给房间内所有人
        public void Broadcast(string op, Action<IWriteableBuffer> cb)
        {
            foreach (var s in ss)
            {
                if (s == null)
                    continue;

                s.Conn.Send2Usr(op, cb);
            }

            var wb = new WriteBuffer(true);
            cb.SC(wb);

            var rb = new RingBuffer(true, true);
            rb.Write(wb.Data, 0, wb.Available);
            currentBattleMsgHistory.Add(new KeyValuePair<string, IReadableBuffer>(op, rb));
        }

        // 战斗开始
        public override void BattleBegin(int randomSeed)
        {
            base.BattleBegin(randomSeed);
            timeElapsed = 0;
            currentBattleMsgHistory.Clear();
            Broadcast("BattleBegin", (buff) =>
            {
                buff.Write(randomSeed);
                buff.Write(Lv.LevelID);
                buff.Write(WinnerAward);
                buff.Write(LoserAward);
                buff.Write(WinnerAwardUnits);
                buff.Write(ID);
                buff.Write(UsrsID);
                buff.Write(UsrsInfo);
                buff.Write(Map.Size);
            });

            if (ComputerAI != null)
                ComputerAI.Start();
        }

        // 战斗结束
        public override void BattleEnd(string winner)
        {
            if (ComputerAI != null)
                ComputerAI.Destroy();

            base.BattleEnd(winner);

            // 记录胜负场次
            UserInfo winnerInfo = null;
            UserInfo loserInfo = null;
            if (winner != null /* null 是平局情况，算两人都输 */)
            {
                if (winner == UsrsID[1])
                {
                    winnerInfo = UsrsInfo[1];
                    loserInfo = UsrsInfo[2];
                }
                else if (winner == UsrsID[2])
                {
                    winnerInfo = UsrsInfo[2];
                    loserInfo = UsrsInfo[1];
                }

                if (winnerInfo != null)
                {
                    winnerInfo.Coins += WinnerAward;
                    if (WinnerAwardUnits != null)
                        foreach (var c in WinnerAwardUnits)
                            if (winnerInfo.GetCardLv(c) == 0)
                                winnerInfo.AddUnit(c);
                }

                if (UsrsInfo[1] != winnerInfo)
                    UsrsInfo[1].Coins += LoserAward;

                if (UsrsInfo[2] != winnerInfo)
                    UsrsInfo[2].Coins += LoserAward;
            }

            // PVE 通关记录
            if (winner != null)
            {
                if (!IsPVP)
                    GetUserInfo(winner).AddPassedPVELevel(Lv.LevelID);
                else
                {
                    winnerInfo.WinCount++;
                    loserInfo.LoseCount++;
                }
            }

            // 发放战斗奖励
            foreach (var s in ss)
            {
                if (s.ID != UsrsID[1] && s.ID != UsrsID[2])
                    continue;

                s.Usr.Update();
            }

            // 广播结果
            Broadcast("BattleEnd", (buff) =>
            {
                buff.Write(winner);
            });

            // 保存录像
            SaveCurrentBattleReplay(UsrsID[1], UsrsID[2], IsPVP, currentBattleMsgHistory);
        }

        // 逻辑时间流逝
        Fix64 timeElapsed = 0;
        public void OnTimeElapsed(int te)
        {
            if (!Started)
                return;

            timeElapsed += te;
            if (timeElapsed >= FrameInterval)
            {
                timeElapsed -= FrameInterval;

                // MoveOneStep 和发送 "FrameMoveForward" 消息之间不可插入任何其它逻辑，否则
                // 插入在中间的逻辑，和客户端数据会差一帧
                MoveOneStep();
                if (!Started) // 可能已经结束了
                    return;

                Broadcast("FF", null); // (buff) => { buff.Write(FrameNo); });

                if (ComputerAI != null)
                    ComputerAI.OnTimeElapsed(te);
            }
        }

        #region 处理客户端消息

        Dictionary<string, Action<int, IReadableBuffer>> messageHandlers = null;
        public void OnMessage(string op, string usr, IReadableBuffer data)
        {
            if (messageHandlers == null)
            {
                messageHandlers = new Dictionary<string, Action<int, IReadableBuffer>>()
                {
                    { "SetPath", OnSetPath },
                    { "ConstructBuilding", OnConstructBuilding },
                    { "CancelBuilding", OnCancelBuilding },
                    { "BuildingLevelUp", OnBuildingLevelUp },
                    { "ConstructBattleUnit", OnConstructBattleUnit },
                    { "ConstructAccessoryUnit", OnConstructAccessoryUnit },
                    { "DropSoldierFromCarrier", OnDropSoldierFromCarrier },
                    { "ReleaseBattleUnits", OnReleaseBattleUnits },
                };
            }

            var player = GetNoByUser(usr);
            messageHandlers[op](player, data);
        }

        // 设置行进目标
        void OnSetPath(int player, IReadableBuffer data)
        {
            var uid = data.ReadString();
            var u = GetUnit(uid);
            if (u == null || u.Player != player || u.cfg.OutOfControl)
                return;

            var path = data.ReadVec2Arr();
            var ignoreTarget = data.ReadBool();
            SrvSetPath(u, path, ignoreTarget);
        }
        public void SrvSetPath(Unit u, Vec2[] path, bool ignoreTarget)
        {
            u.ResetPath(path);
            u.IgnoreTargetWhenMoving = ignoreTarget;
            Broadcast("SetPath", (buff) => { buff.Write(u.UID); buff.Write(path); buff.Write(ignoreTarget); });
        }

        // 建造建筑
        void OnConstructBuilding(int player, IReadableBuffer data)
        {
            var constructUnitType = data.ReadString();
            var pos = data.ReadVec2();

            if (UsrsInfo[player].GetCardLv(constructUnitType) <= 0)
                return;

            SrvConstructBuilding(player, constructUnitType, pos);
        }
        public void SrvConstructBuilding(int player, string constructUnitType, Vec2 pos)
        {
            var u = ConstructBuilding(constructUnitType, pos, player);
            if (u == null)
                return;

            Broadcast("CosntructBuildingUnit", (buff) =>
            {
                buff.Write(constructUnitType);
                buff.Write(player);
                buff.Write(pos);
            });
        }

        // 取消建造
        void OnCancelBuilding(int player, IReadableBuffer data)
        {
            var uid = data.ReadString();
            var u = GetUnit(uid);
            if (u == null)
                return;

            SrvCancelBuilding(u);
        }
        public void SrvCancelBuilding(Unit u)
        {
            u.Room.CancelBuilding(u);
            Broadcast("CancelBuilding", (buff) =>
            {
                buff.Write(u.UID);
            });
        }

        // 建筑升级
        void OnBuildingLevelUp(int player, IReadableBuffer data)
        {
            var uid = data.ReadString();
            var toType = data.ReadString();

            SrvBuildingLevelUp(uid, toType);
        }
        public void SrvBuildingLevelUp(string uid, string toType)
        {
            if (!BuildingLevelUp(uid, toType))
                return;

            Broadcast("BuildingLevelUp", (buff) =>
            {
                buff.Write(uid);
                buff.Write(toType);
            });
        }

        // 建造作战单位
        void OnConstructBattleUnit(int player, IReadableBuffer data)
        {
            var buildingUID = data.ReadString();
            var genType = data.ReadString();
            var building = GetUnit(buildingUID);
            if (building == null)
                return;

            if (building.Player != player)
                return;

            SrvConstructBattleUnit(building, genType);
        }
        public void SrvConstructBattleUnit(Unit building, string genType)
        {
            if (!ConstructBattleUnit(building, genType))
                return;

            Broadcast("ConstructBattleUnit", (buff) =>
            {
                buff.Write(building.UID);
                buff.Write(genType);
            });
        }

        // 直接放置单位
        public void SrvAddUnitAt(int player, string type, int num, Vec2 pos)
        {
            FC.For(num, (i) => { AddNewUnit(null, type, pos, player); });
            Broadcast("AddUnitAt", (buff) =>
            {
                buff.Write(player);
                buff.Write(type);
                buff.Write(num);
                buff.Write(pos);
            });
        }

        // 建造挂件
        void OnConstructAccessoryUnit(int player, IReadableBuffer data)
        {
            var buildingUID = data.ReadString();
            var genType = data.ReadString();
            var building = GetUnit(buildingUID);

            if (building.Player != player)
                return;

            SrvConstructAccessoryUnit(building, genType);
        }
        public void SrvConstructAccessoryUnit(Unit building, string genType)
        {
            var acc = ConstructAccessoryUnit(building, genType);
            if (acc == null)
                return;

            Broadcast("CosntructAccessoryUnit", (buff) =>
            {
                buff.Write(building.UID);
                buff.Write(genType);
            });
        }

        // 投放伞兵
        void OnDropSoldierFromCarrier(int player, IReadableBuffer data)
        {
            var dropPt = data.ReadVec2();
            SrvDropSoldierFromCarrier(player, dropPt);
        }
        public void SrvDropSoldierFromCarrier(int player, Vec2 dropPt)
        {
            if (!CreateSoldierCarrier(player, dropPt))
                return;

            Broadcast("DropSoldierFromCarrier", (buff) =>
            {
                buff.Write(player);
                buff.Write(dropPt);
            });
        }

        // 释放部队
        void OnReleaseBattleUnits(int player, IReadableBuffer data)
        {
            var uid = data.ReadString();
            var u = GetUnit(uid);
            if (u == null)
                return;

            var pt = data.ReadVec2();
            SrvReleaseBattleUnits(u, pt);
        }
        void SrvReleaseBattleUnits(Unit u, Vec2 pt)
        {
            ReleaseBattleUnits(u, pt);
            Broadcast("ReleaseBattleUnits", (buff) =>
            {
                buff.Write(u.UID);
                buff.Write(pt);
            });
        }

        #endregion

        #region Replay related

        // 当前战斗的历史消息
        List<KeyValuePair<string, IReadableBuffer>> currentBattleMsgHistory = new List<KeyValuePair<string, IReadableBuffer>>();

        // 所有录像
        static StableDictionary<string, List<KeyValuePair<string, IReadableBuffer>>> replays = new StableDictionary<string, List<KeyValuePair<string, IReadableBuffer>>>();
        public static StableDictionary<string, List<KeyValuePair<string, IReadableBuffer>>> Replays
        {
            get
            {
                return replays;
            }
        }

        // 获取所有录像名称列表
        public static string[] AllReplayTitles { get { return replays.KeyArray; } }

        // 获取指定录像
        public static List<KeyValuePair<string, IReadableBuffer>> GetReplay(string r)
        {
            return replays.ContainsKey(r) ? replays[r] : null;
        }

        // 加载所有录像
        static int nextReplayNo = 0;
        public static void LoadAllPVPReplays()
        {
            if (!Directory.Exists(ReplayFolder))
                Directory.CreateDirectory(ReplayFolder);

            // 获取所有文件名并排序
            var fs = Directory.GetFiles(ReplayFolder, "*.scm", SearchOption.TopDirectoryOnly);
            fs.SwiftSort((f) =>
            {
                var pureFileName = Path.GetFileNameWithoutExtension(f);
                return int.Parse(pureFileName.Substring(0, pureFileName.IndexOf(".")));
            });

            if (fs.Length > 0)
            {
                var lastFile = Path.GetFileNameWithoutExtension(fs[fs.Length - 1]);
                nextReplayNo = int.Parse(lastFile.Substring(0, lastFile.IndexOf(".")));
            }

            nextReplayNo++;

            fs = fs.ToArray((i, f, skipAct) => // 过滤 PVE 的录像，不放入点播列表
            {
                var n = f.IndexOf(".");
                if (f.Substring(n, 5) != ".PVP.")
                    skipAct();

                return f;
            });

            // 读取所有录像内容
            foreach (var f in fs)
            {
                byte[] data = null;
                using (var fr = new BinaryReader(new FileStream(f, FileMode.Open)))
                    data = fr.ReadBytes((int)fr.BaseStream.Length);

                var replay = ReplayUtils.ReadReplay(new RingBuffer(data));
                replays[Path.GetFileNameWithoutExtension(f)] = replay;
            }
        }

        // 战斗录像存放地址
        static string ReplayFolder = "Replays";
        public static void SaveCurrentBattleReplay(string usr1, string usr2, bool isPVP, List<KeyValuePair<string, IReadableBuffer>> msgs)
        {
            if (!Directory.Exists(ReplayFolder))
                Directory.CreateDirectory(ReplayFolder);

            var strData = DateTime.Now.ToShortDateString().Replace("/", "_");
            var strTime = DateTime.Now.ToShortTimeString().Replace(":", "_");
            var f = (nextReplayNo++).ToString().PadLeft(10, '0') + (isPVP ? ".PVP." : ".PVE.") + strData + "." + strTime + "." + usr1 + ".vs." + usr2;

            if (isPVP)
                replays[f] = msgs;

            var writer = new WriteBuffer();
            ReplayUtils.WriteReplay(msgs, writer);
            using (var fw = new BinaryWriter(new FileStream(Path.Combine(ReplayFolder, f + ".scm"), FileMode.CreateNew)))
                fw.Write(writer.Data, 0, writer.Available);
        }

        #endregion

        #region 电脑 AI 相关

        public AIComputerOpponent ComputerAI { get; protected set; }

        public AIComputerOpponent CreateComputerAI(string aiType, int player)
        {
            ComputerAI = CreateAI(aiType, player);
            ComputerAI.Init();
            return ComputerAI;
        }

        AIComputerOpponent CreateAI(string aiType, int player)
        {
            var aiID = ID + "_ai_" + (aiType == null ? "null" : aiType);
            switch (aiType)
            {
                case "PVE002":
                    return new AIPVE002(aiID, this, player);
                case "PVE001":
                case "PVE003":
                default:
                    return new Dumb(aiID, this, player);
            }
        }

        #endregion
    }
}
